package com.kk.datastructure.linkedlist.doublea;

/**
 * title: 双向链表
 * @author 阿K
 * 2020年11月26日 下午9:46:14 
 */
public class DoubleLinkedListDemo {
	public static void main(String[] args) {
		// 测试
		System.out.println("双向链表的测试");
		// 先创建节点
		HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
		HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
		HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
		HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
		// 创建一个双向链表
		DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
//		doubleLinkedList.add(hero1);
//		doubleLinkedList.add(hero2);
//		doubleLinkedList.add(hero3);
//		doubleLinkedList.add(hero4);

		doubleLinkedList.addByOrder(hero1);
		doubleLinkedList.addByOrder(hero4);
		doubleLinkedList.addByOrder(hero3);
		doubleLinkedList.addByOrder(hero2);

		doubleLinkedList.list();

//		// 修改
//		HeroNode newHeroNode = new HeroNode(4, "公孙胜", "入云龙");
//		doubleLinkedList.update(newHeroNode);
//		System.out.println("修改后的链表情况");
//		doubleLinkedList.list();
////
//		// 删除
//		doubleLinkedList.delete(3);
//		System.out.println("删除后的链表情况~~");
//		doubleLinkedList.list();
	}

}

// 修改和遍历不变和单链表一样
class DoubleLinkedList {

	// 先初始化一个头节点,头节点不能动,不存放具体的数据（可以理解为王伦 -- 初代寨主，后被林冲捅了）
	private HeroNode head = new HeroNode(0, null, null);

	// 返回头结点
	public HeroNode getHead() {
		return head;
	}

	// 乱序添加
	public void add(HeroNode heroNode) {

		// 辅助
		HeroNode temp = head;
		// 找到最后一个
		while (temp.next != null) {
			temp = temp.next;
		}

		// 插入到最后
		temp.next = heroNode;
		heroNode.pre = temp;
	}

	// 有序添加
	public void addByOrder(HeroNode heroNode) {
		// 因为头节点不能动，因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
		// 因为单链表，因为我们找的temp 是位于 添加位置的前一个节点，否则插入不了
		HeroNode temp = head;
		boolean flag = false;// flag标志添加的编号是否存在，默认为false
		while (true) {
			if (temp.next == null)
				break;
			if (temp.next.no > heroNode.no)
				// 位置找到，就在 temp后面
				// 因为 它满足了 按顺序 ，所以可以插入
				break;
			if (temp.next.no == heroNode.no) {
				// 已经存在改排行的编号(不可重复)
				flag = true;
				break;
			}
			// 没满足以上，后移下一次节点继续找
			temp = temp.next;
		}

		// 对 flag 进行判断
		if (flag)
			// 不能添加，说明编号已经存在
			System.out.printf("准备插入的英雄的编号 %d 已经存在了, 不能加入\n", heroNode.no);
		else {
			// 插入到链表中，temp的后面
			temp.next = heroNode;// 我后面是你
			temp = heroNode.pre;
		}
	}

	// 删除
	public void delete(int no) {

		// 判空
		if (head.next == null)
			return;

		HeroNode temp = head.next;// 不在是需要前一个来删除
		boolean flag = false;// 标志是否找到待删除节点
		while (true) {
			if (temp.next == null)
				// 已经到链表的最后
				break;
			if (temp.next.no == no) {
				// 已经找到
				flag = true;
				break;
			}
			// 移动继续找
			temp = temp.next;
		}
		// 通过 flag 进行判断
		if (flag) {
			temp.pre.next = temp.next;// 我前面说他后面 是 我后面
			// 这里我们的代码有问题?
			// 如果是最后一个节点，就不需要执行下面这句话，否则出现空指针
			if (temp.next != null)
				temp.next.pre = temp.pre;// 我后面说他前面 是 我前面
		} else
			System.out.printf("没有找到排行为【%d】要修改的英雄", no);
	}

	// 更新节点的信息, 根据no编号来修改，即no编号不能改
	public void update(HeroNode heroNode) {
		// 判空
		if (head.next == null) {
			System.out.println("链表为空~~");
			return;
		}
		// 根据 no 找到需要修改的节点
		// 定义一个辅助变量
		HeroNode temp = head.next;
		boolean flag = false;// 表示是否找到节点
		while (true) {
			if (temp == null)
				// 链表已经遍历完
				break;
			if (temp.no == heroNode.no) {
				// 节点已经找到
				flag = true;
				break;
			}
			// 节点移动，继续找
			temp = temp.next;
		}

		// 根据 flag 判断
		if (flag) {
			// 找到，修改姓名和外号
			temp.name = heroNode.name;
			temp.nickname = heroNode.nickname;
		} else {
			System.out.printf("没有找到排行为【%d】要修改的英雄", heroNode.no);
		}
	}

	// 遍历链表
	public void list() {
		// 判断链表是否为空
		if (head.next == null) {
			System.out.println("链表为空~~~");
			return;
		}
		// 因为头节点，不能动，因此我们需要一个辅助变量来遍历
		HeroNode temp = head.next;

		while (true) {
			// 判断是否到链表的最后
			if (temp == null)
				return;

			// 输出节点信息
			System.out.println(temp);
			// 将节点后移，注意要加！！
			temp = temp.next;
		}
	}
}

//定义HeroNode ， 每个HeroNode 对象就是一个节点
class HeroNode {
	public int no; // 好汉排行
	public String name; // 好汉姓名
	public String nickname;// 好汉外号
	public HeroNode next; // 指向下一个节点（好汉），默认为Null
	public HeroNode pre; // 指向上一个节点（好汉），默认为Null
	// 构造器

	public HeroNode(int no, String name, String nickname) {
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}

	// 为了显示方法，我们重新toString
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}

}

